package com.dong.multithreading;

import org.junit.Test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Lock
 */
public class DoLock {

    /*
     * 1.Lock
     *   public interface Lock {
     *      void lock();
     *      void lockInterruptibly() throws InterruptedException;
     *      boolean tryLock();
     *      boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
     *      void unlock();
     *      Condition newCondition();
     *   }
     *  采用Lock，必须主动去释放锁，并且在发生异常时，不会自动释放锁。因此一般来说，使用Lock必须在try{}catch{}块中进行，并且将释放锁的操作放在finally块中进行，以保证锁一定被被释放，防止死锁的发生。
     *
     *  lock()方法是平常使用得最多的一个方法，就是用来获取锁。如果锁已被其他线程获取，则进行等待；
     *  tryLock()方法是有返回值的，它表示用来尝试获取锁，如果获取成功，则返回true，如果获取失败（即锁已被其他线程获取），则返回false，也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待；
     *  tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的，只不过区别在于这个方法在拿不到锁时会等待一定的时间，在时间期限之内如果还拿不到锁，就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁，则返回true；
     *  lockInterruptibly()方法比较特殊，当通过这个方法去获取锁时，如果线程正在等待获取锁，则这个线程能够响应中断，即中断线程的等待状态。也就使说，当两个线程同时通过lock.lockInterruptibly()想获取某个锁时，假若此时线程A获取到了锁，而线程B只有在等待，那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程；
     *
     * 2.ReentrantLock
     *
     * 3.ReadWriteLock
     *   一个用来获取读锁，一个用来获取写锁。也就是说将文件的读写操作分开，分成2个锁来分配给线程，从而使得多个线程可以同时进行读操作。下面的ReentrantReadWriteLock实现了ReadWriteLock接口。
     *
     * 4.ReentrantReadWriteLock
     *  不过要注意的是，如果有一个线程已经占用了读锁，则此时其他线程如果要申请写锁，则申请写锁的线程会一直等待释放读锁。
     *  如果有一个线程已经占用了写锁，则此时其他线程如果申请写锁或者读锁，则申请的线程会一直等待释放写锁。
     */

    @Test
    public void test1() {
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            System.out.println(1);
            lock.lock();
            System.out.println(2);
        } finally {
            lock.unlock();
        }
    }

    @Test
    public void test2() {
        ReadWriteLock lock = new ReentrantReadWriteLock();
        lock.readLock();
        System.out.println(1);
        lock.readLock();
        System.out.println(2);
    }
}
